package com.genoworks.gcconsole;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;

public class ConsoleWriter implements GcListener {
  private static final DecimalFormat TOTAL_MEM_FORMAT = new DecimalFormat( "###,##0.00" );

  private int columns = 132;

  private SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss.SSS" );

  private PrintWriter out = null;

  public ConsoleWriter( Writer writer ) {
    if ( writer instanceof PrintWriter ) {
      out = (PrintWriter) writer;
    } else {
      out = new PrintWriter( writer );
    }
  }

  public ConsoleWriter( OutputStream writer ) {
    this( new OutputStreamWriter( writer ) );
  }

  public void setDateFormat( SimpleDateFormat format ) {
    dateFormat = format;
  }

  public void onGarbageCollection( GcEvent event ) {
    //    System.out.println( event.toString() );
    try {

      //
      final StringBuilder graph = new StringBuilder();

      //
      graph.append( dateFormat.format( event.getAt() ) );
      graph.append( ' ' );

      /**
       * full인지 일반인지?
       */
      if ( event.isFullSystem() ) {
        graph.append( "S" );
      } else if ( event.isFull() ) {
        graph.append( "F" );
      } else {
        graph.append( " " );
      }

      //
      final String totalMem = TOTAL_MEM_FORMAT.format( event.getMax() / 1024.0D / 1024 ) + "M";

      //
      final int graphLength = columns - graph.length() - totalMem.length() - 1;
      graph.append( '|' );
      for ( int i = 0; i < graphLength; i++ ) {
        graph.append( ' ' );
      }
      graph.append( '|' );

      //
      final long young = event.getYoungGenPost();
      final long old = event.getOldGenPost();
      final long perm = event.getPermGenPost();
      final long heap = event.getHeapPost();
      if ( young > 0 ) {
        graph.setCharAt( getPosition( young, event.getMax(), graphLength ), 'Y' );
      }
      if ( old > 0 ) {
        graph.setCharAt( getPosition( old, event.getMax(), graphLength ), 'O' );
      }
      if ( perm > 0 ) {
        graph.setCharAt( getPosition( perm, event.getMax(), graphLength ), 'P' );
      }
      if ( heap > 0 ) {
        graph.setCharAt( getPosition( heap, event.getMax(), graphLength ), 'H' );
      }

      //
      graph.append( ' ' );
      graph.append( totalMem );

      //
      //      System.out.println( graph.toString() );
      out.println( graph.toString() );
      out.flush();

    } catch( Throwable t ) {
      t.printStackTrace();
      System.exit( 0 );
    }
  }

  private int getPosition( long curMem, long maxMem, int graphLength ) {
    //    (columns-2) : result = Runtime.getRuntime().maxMemory() : curMem;
    //    System.out.println( "graphLength=" + graphLength + ",curMem=" + curMem + ",max=" + maxMem );
    return ( columns - graphLength ) + (int) ( 1.0D * ( graphLength - 1 ) * curMem / maxMem ) - 1;
  }

  public void setNumberOfColumns( int numCols ) {
    if ( numCols <= 0 ) {
      return;
    }
    columns = numCols;
  }
}
